package com.cu.employmentmanagementsystem.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cu.employmentmanagementsystem.common.constants.AuthConstant;
import com.cu.employmentmanagementsystem.common.convert.UserDTOConverter;
import com.cu.employmentmanagementsystem.common.enums.IsDeleteFlagEnum;
import com.cu.employmentmanagementsystem.common.enums.UserRoleEnum;
import com.cu.employmentmanagementsystem.common.enums.UserStatusEnum;
import com.cu.employmentmanagementsystem.dao.*;
import com.cu.employmentmanagementsystem.dto.UserDTO;
import com.cu.employmentmanagementsystem.entity.*;
import com.cu.employmentmanagementsystem.common.exception.CommonException;
import com.cu.employmentmanagementsystem.service.UserService;
import com.cu.employmentmanagementsystem.util.CommonUtils;
import com.cu.employmentmanagementsystem.util.RedisUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 25853
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2024-07-01 13:20:17
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService
{


    private final RoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;
    private final RedisUtil redisUtil;
    private final RolePermissionMapper rolePermissionMapper;
    private final PermissionMapper permissionMapper;
    private final StudentInformationDao studentInformationDao;
    private final AdminDao adminDao;
    private final CompanyDao companyDao;
    private final StudentVitaDao studentVitaDao;
    private final StudentRecruitmentDao studentRecruitmentDao;

    public UserServiceImpl(RoleMapper roleMapper, UserRoleMapper userRoleMapper,
                           RedisUtil redisUtil, RolePermissionMapper rolePermissionMapper,
                           PermissionMapper permissionMapper,
                           StudentInformationDao studentInformationDao,
                           AdminDao adminDao, CompanyDao companyDao, @Qualifier("studentVitaDao") StudentVitaDao studentVitaDao, StudentRecruitmentDao studentRecruitmentDao)
    {
        this.roleMapper = roleMapper;
        this.userRoleMapper = userRoleMapper;
        this.redisUtil = redisUtil;
        this.rolePermissionMapper = rolePermissionMapper;
        this.permissionMapper = permissionMapper;
        this.studentInformationDao = studentInformationDao;
        this.adminDao = adminDao;
        this.companyDao = companyDao;
        this.studentVitaDao = studentVitaDao;
        this.studentRecruitmentDao = studentRecruitmentDao;
    }

    @Override
    public Boolean register(UserDTO userDTO)
    {
        User user = UserDTOConverter.INSTANCE.convertDTOToEntity(userDTO);
        user.setStatus(UserStatusEnum.OPEN.getCode());
        user.setIsDeleted(IsDeleteFlagEnum.UN_DELETED.getCode());
        Long roleIndex = userDTO.getRoleIndex() != null ? userDTO.getRoleIndex() : 0;
        user.setPassword(StringUtils.isNotBlank(user.getPassword()) ? SaSecureUtil.md5BySalt(user.getPassword(), user.getAccount()) : null);
        String account = StringUtils.isNotBlank(user.getAccount()) ? user.getAccount() : String.valueOf(System.currentTimeMillis());
        if (this.checkUserExist(user))
        {
            throw new CommonException("该账号已存在");
        }
        user.setAccount(account);
        boolean insertUserResult = this.save(user);

//        UserDTO tempUserDto = UserDTOConverter.INSTANCE.convertEntityToDTO(user);
//        tempUserDto.setRoleId(roleId);
        userDTO.setId(user.getId());
        Boolean insertInfoResult = insertInfo(userDTO);

        Role role = new Role();
        role.setRoleKey(UserRoleEnum.getRoleByCode(roleIndex));
        Role roleResult = roleMapper.selectOne(
                new LambdaQueryWrapper<Role>()
                        .eq(Role::getRoleKey, role.getRoleKey())
        );

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(roleResult.getId());
        userRole.setIsDeleted(IsDeleteFlagEnum.UN_DELETED.getCode());
        String roleKey = redisUtil.buildKey(AuthConstant.AUTH_ROLE_PREFIX, user.getAccount());
        redisUtil.set(roleKey, JSON.toJSONString(roleResult));
        boolean insertUserRoleResult = userRoleMapper.insert(userRole) > 0;

        String permissionKey = redisUtil.buildKey(AuthConstant.AUTH_PERMISSION_PREFIX, user.getAccount());
        RolePermission rolePermission = new RolePermission();
        rolePermission.setRoleId(roleResult.getId());
        List<RolePermission> rolePermissionList = rolePermissionMapper.selectList(
                new LambdaQueryWrapper<RolePermission>()
                        .eq(RolePermission::getRoleId, rolePermission.getRoleId())
        );
        List<Long> permissionIdList = rolePermissionList.stream().map(RolePermission::getPermissionId).collect(Collectors.toList());
        List<Permission> permissionList = permissionMapper.selectBatchIds(permissionIdList);
        redisUtil.set(permissionKey, JSON.toJSONString(permissionList));

        return insertUserResult && insertUserRoleResult && insertInfoResult;
    }

    @Override
    public Boolean update(UserDTO userDTO)
    {
        int updateOtherInfoResult = 0;
        switch (userDTO.getRole())
        {
            case AuthConstant.STUDENT:
                StudentInformation studentInformation = userDTO.getStudentInformation();
                updateOtherInfoResult = studentInformationDao.update(studentInformation);
                break;
            case AuthConstant.ADMIN:
                Admin admin = userDTO.getAdmin();
                updateOtherInfoResult = adminDao.update(admin);
                break;
            case AuthConstant.COMPANY:
                Company company = userDTO.getCompany();
                updateOtherInfoResult = companyDao.update(company);
                break;
        }

        User user = UserDTOConverter.INSTANCE.convertDTOToEntity(userDTO);
        boolean updateUserResult = this.updateById(user);
        return updateUserResult && updateOtherInfoResult > 0;
    }

    @Override
    public Boolean delete(User user)
    {
        user.setIsDeleted(IsDeleteFlagEnum.DELETED.getCode());
        return this.updateById(user);
    }

    @Override
    public SaTokenInfo loginByValidCode(String validCode)
    {
        String key = redisUtil.buildKey(AuthConstant.LOGIN_CODE_PREFIX, validCode);
        String openId = redisUtil.get(key);
        if (StringUtils.isBlank(openId))
        {
            return null;
        }
        User user = new User();
        user.setOpenId(openId);
        if (checkUserExist(user))
        {
            UserDTO userDTO = UserDTOConverter.INSTANCE.convertEntityToDTO(user);
            this.register(userDTO);
        } else
        {
            User dbUser = this.getOne(
                    new LambdaQueryWrapper<User>()
                            .eq(User::getOpenId, user.getOpenId())
            );
            StpUtil.login(dbUser.getAccount());
        }
        redisUtil.del(key);
        return StpUtil.getTokenInfo();
    }

    @Override
    public UserDTO getUserInfo()
    {
        User user = CommonUtils.getUser();
        UserDTO userDTO = UserDTOConverter.INSTANCE.convertEntityToDTO(user);
        String userRole = CommonUtils.getUserRole();
        switch (userRole)
        {
            case AuthConstant.STUDENT:
                StudentInformation studentInformation = CommonUtils.getStudentInformation();
                userDTO.setStudentInformation(studentInformation);
                break;
            case AuthConstant.ADMIN:
                Admin admin = CommonUtils.getAdmin();
                userDTO.setAdmin(admin);
                break;
            case AuthConstant.COMPANY:
                Company company = CommonUtils.getCompany();
                userDTO.setCompany(company);
                break;
        }
        userDTO.setRole(userRole);
        return userDTO;
    }

    private Boolean insertInfo(UserDTO userDTO)
    {
        Long roleId = userDTO.getRoleIndex();
        Long userId = userDTO.getId();
        int result = 0;
        switch (UserRoleEnum.getRoleByCode(roleId))
        {
            case AuthConstant.STUDENT:
                StudentInformation studentInformation = new StudentInformation();
                studentInformation.setUserId(userId);
                result = studentInformationDao.insert(studentInformation);
                break;
            case AuthConstant.ADMIN:
                Admin admin = new Admin();
                admin.setUserId(userId);
                result = adminDao.insert(admin);
                break;
            case AuthConstant.COMPANY:
                Company company = new Company();
                company.setUserId(userId);
                result = companyDao.insert(company);
                break;
        }
        return result > 0;
    }

    @Override
    public SaTokenInfo loginByPassword(User user)
    {
        if (StringUtils.isNotBlank(user.getAccount()) && StringUtils.isNotBlank(user.getPassword()))
        {
            User userResult = this.getOne(
                    new LambdaQueryWrapper<User>()
                            .eq(User::getAccount, user.getAccount())
                            .eq(User::getPassword, SaSecureUtil.md5BySalt(user.getPassword(), user.getAccount()))
            );
            if (userResult != null)
            {
                StpUtil.login(userResult.getAccount());
                return StpUtil.getTokenInfo();
            }
        }
        return null;
    }

    @Override
    public User getUserInfoByAccount(String userAccount)
    {
        return this.getOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getAccount, userAccount)
        );
    }

    @Override
    public boolean checkUserExist(User user)
    {
        return this.count(
                new LambdaQueryWrapper<User>()
                        .eq(User::getAccount, user.getAccount())
                        .or()
                        .eq(User::getOpenId, user.getOpenId())
                        .or()
                        .eq(User::getId, user.getId())
        ) > 0;
    }

    @Override
    public Integer getFlowIndex()
    {
        int index = 0;
        Long studentId = CommonUtils.getStudentId();
        //有没有简历
        StudentVita vita = studentVitaDao.selectByStudentId(studentId);
        if(vita == null)
        {
            return index;
        }
        index++;
        //简历有没有通过
        if (vita.getPeviewStatus() == -1)
        {
            return index;
        }
        index++;
        if(vita.getPeviewStatus() == 0)
        {
            return index;
        }
        index++;
        //有没有投递简历
        List<StudentRecruitment> studentRecruitmentList = studentRecruitmentDao.queryByresumeId(vita.getId());
        if(studentRecruitmentList.isEmpty())
        {
            return index;
        }
        index++;
        //有没有被录用
        for (StudentRecruitment studentRecruitment : studentRecruitmentList)
        {
            if(studentRecruitment.getDeliveryStatus() == 1)
            {
                return index;
            }
        }


        return index;
    }
}




